//===--- DeclContext.cpp - DeclContext implementation ---------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "polarphp/ast/DeclContext.h"
#include "polarphp/ast/AccessScope.h"
#include "polarphp/ast/AstContext.h"
#include "polarphp/ast/AstWalker.h"
#include "polarphp/ast/Expr.h"
#include "polarphp/ast/FileUnit.h"
#include "polarphp/ast/GenericEnvironment.h"
#include "polarphp/ast/Initializer.h"
#include "polarphp/ast/LazyResolver.h"
#include "polarphp/ast/Module.h"
#include "polarphp/ast/ParseRequests.h"
#include "polarphp/ast/SourceFile.h"
#include "polarphp/ast/Types.h"
#include "polarphp/ast/TypeCheckRequests.h"
#include "polarphp/basic/SourceMgr.h"
#include "polarphp/basic/Statistic.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/raw_ostream.h"

namespace polar {

using llvm::dyn_cast;
using llvm::dyn_cast_or_null;

#define DEBUG_TYPE "Name lookup"

STATISTIC(NumLazyIterableDeclContexts,
          "# of serialized iterable declaration contexts");
STATISTIC(NumUnloadedLazyIterableDeclContexts,
          "# of serialized iterable declaration contexts never loaded");

// Only allow allocation of DeclContext using the allocator in AstContext.
void *DeclContext::operator new(size_t Bytes, AstContext &C,
                                unsigned Alignment) {
   return C.Allocate(Bytes, Alignment);
}

AstContext &DeclContext::getAstContext() const {
   return getParentModule()->getAstContext();
}

GenericTypeDecl *DeclContext::getSelfTypeDecl() const {
   auto decl = const_cast<Decl*>(getAsDecl());
   if (!decl) return nullptr;

   auto ext = dyn_cast<ExtensionDecl>(decl);
   if (!ext) return dyn_cast<GenericTypeDecl>(decl);

   return ext->getExtendedNominal();
}

/// If this DeclContext is a NominalType declaration or an
/// extension thereof, return the NominalTypeDecl.
NominalTypeDecl *DeclContext::getSelfNominalTypeDecl() const {
   return dyn_cast_or_null<NominalTypeDecl>(getSelfTypeDecl());
}


ClassDecl *DeclContext::getSelfClassDecl() const {
   return dyn_cast_or_null<ClassDecl>(getSelfTypeDecl());
}

EnumDecl *DeclContext::getSelfEnumDecl() const {
   return dyn_cast_or_null<EnumDecl>(getSelfTypeDecl());
}

StructDecl *DeclContext::getSelfStructDecl() const {
   return dyn_cast_or_null<StructDecl>(getSelfTypeDecl());
}

InterfaceDecl *DeclContext::getSelfInterfaceDecl() const {
   return dyn_cast_or_null<InterfaceDecl>(getSelfTypeDecl());
}

InterfaceDecl *DeclContext::getExtendedInterfaceDecl() const {
   if (auto decl = const_cast<Decl*>(getAsDecl()))
      if (auto ED = dyn_cast<ExtensionDecl>(decl))
         return dyn_cast_or_null<InterfaceDecl>(ED->getExtendedNominal());
   return nullptr;
}

GenericTypeParamType *DeclContext::getInterfaceSelfType() const {
   assert(getSelfInterfaceDecl() && "not a protocol");

   GenericParamList *genericParams;
   if (auto proto = dyn_cast<InterfaceDecl>(this)) {
      genericParams = proto->getGenericParams();
   } else {
      genericParams = cast<ExtensionDecl>(this)->getGenericParams();
   }

   if (genericParams == nullptr)
      return nullptr;

   return genericParams->getParams().front()
      ->getDeclaredInterfaceType()
      ->castTo<GenericTypeParamType>();
}

Type DeclContext::getDeclaredTypeInContext() const {
   if (auto declaredType = getDeclaredInterfaceType())
      return mapTypeIntoContext(declaredType);
   return Type();
}

Type DeclContext::getDeclaredInterfaceType() const {
   if (auto *ED = dyn_cast<ExtensionDecl>(this)) {
      auto *NTD = ED->getExtendedNominal();
      if (NTD == nullptr)
         return ErrorType::get(ED->getAstContext());
      return NTD->getDeclaredInterfaceType();
   }
   if (auto *NTD = dyn_cast<NominalTypeDecl>(this))
      return NTD->getDeclaredInterfaceType();
   return Type();
}

void DeclContext::forEachGenericContext(
   llvm::function_ref<void (GenericParamList *)> fn) const {
   auto dc = this;
   do {
      if (auto decl = dc->getAsDecl()) {
         // Extensions do not capture outer generic parameters.
         if (auto *ext = dyn_cast<ExtensionDecl>(decl)) {
            for (auto *gpList = ext->getGenericParams();
                 gpList != nullptr;
                 gpList = gpList->getOuterParameters()) {
               fn(gpList);
            }

            return;
         }

         if (auto genericCtx = decl->getAsGenericContext())
            if (auto *gpList = genericCtx->getGenericParams())
               fn(gpList);
      }
   } while ((dc = dc->getParent()));
}

unsigned DeclContext::getGenericContextDepth() const {
   unsigned depth = -1;
   forEachGenericContext([&](GenericParamList *) { ++depth; });
   return depth;
}

GenericSignature DeclContext::getGenericSignatureOfContext() const {
   auto dc = this;
   do {
      if (auto decl = dc->getAsDecl())
         if (auto GC = decl->getAsGenericContext())
            return GC->getGenericSignature();
   } while ((dc = dc->getParent()));

   return nullptr;
}

GenericEnvironment *DeclContext::getGenericEnvironmentOfContext() const {
   auto dc = this;
   do {
      if (auto decl = dc->getAsDecl())
         if (auto GC = decl->getAsGenericContext())
            return GC->getGenericEnvironment();
   } while ((dc = dc->getParent()));

   return nullptr;
}

Type DeclContext::mapTypeIntoContext(Type type) const {
   return GenericEnvironment::mapTypeIntoContext(
      getGenericEnvironmentOfContext(), type);
}

DeclContext *DeclContext::getLocalContext() {
   if (isLocalContext())
      return this;
   if (isModuleContext())
      return nullptr;
   return getParent()->getLocalContext();
}

AbstractFunctionDecl *DeclContext::getInnermostMethodContext() {
   auto dc = this;
   do {
      if (auto decl = dc->getAsDecl()) {
         auto func = dyn_cast<AbstractFunctionDecl>(decl);
         // If we found a non-func decl, we're done.
         if (func == nullptr)
            return nullptr;
         if (func->getDeclContext()->isTypeContext())
            return func;
      }
   } while ((dc = dc->getParent()));

   return nullptr;
}

bool DeclContext::isTypeContext() const {
   if (auto decl = getAsDecl())
      return isa<NominalTypeDecl>(decl) || isa<ExtensionDecl>(decl);
   return false;
}

DeclContext *DeclContext::getInnermostTypeContext() {
   auto dc = this;
   do {
      if (dc->isTypeContext())
         return dc;
   } while ((dc = dc->getParent()));

   return nullptr;
}

Decl *DeclContext::getInnermostDeclarationDeclContext() {
   auto DC = this;
   do {
      if (auto decl = DC->getAsDecl())
         return isa<ModuleDecl>(decl) ? nullptr : decl;
   } while ((DC = DC->getParent()));

   return nullptr;
}

DeclContext *DeclContext::getInnermostSkippedFunctionContext() {
   auto dc = this;
   do {
      if (auto afd = dyn_cast<AbstractFunctionDecl>(dc))
         if (afd->isBodySkipped())
            return afd;
   } while ((dc = dc->getParent()));

   return nullptr;
}

DeclContext *DeclContext::getParentForLookup() const {
   if (isa<InterfaceDecl>(this) || isa<ExtensionDecl>(this)) {
      // If we are inside a protocol or an extension, skip directly
      // to the module scope context, without looking at any (invalid)
      // outer types.
      return getModuleScopeContext();
   }
   if (isa<NominalTypeDecl>(this)) {
      // If we are inside a nominal type that is inside a protocol,
      // skip the protocol.
      if (isa<InterfaceDecl>(getParent()))
         return getModuleScopeContext();
   }
   return getParent();
}

ModuleDecl *DeclContext::getParentModule() const {
   const DeclContext *DC = this;
   while (!DC->isModuleContext())
      DC = DC->getParent();
   return const_cast<ModuleDecl *>(cast<ModuleDecl>(DC));
}

SourceFile *DeclContext::getParentSourceFile() const {
   const DeclContext *DC = this;
   while (!DC->isModuleScopeContext())
      DC = DC->getParent();
   return const_cast<SourceFile *>(dyn_cast<SourceFile>(DC));
}

DeclContext *DeclContext::getModuleScopeContext() const {
   auto DC = const_cast<DeclContext*>(this);

   while (true) {
      if (DC->ParentAndKind.getInt() == ASTHierarchy::FileUnit)
         return DC;
      if (auto NextDC = DC->getParent()) {
         DC = NextDC;
      } else {
         assert(isa<ModuleDecl>(DC->getAsDecl()));
         return DC;
      }
   }
}

/// Determine whether the given context is generic at any level.
bool DeclContext::isGenericContext() const {
   auto dc = this;
   do {
      if (auto decl = dc->getAsDecl()) {
         if (auto GC = decl->getAsGenericContext()) {
            if (GC->getGenericParams())
               return true;

            // Extensions do not capture outer generic parameters.
            if (isa<ExtensionDecl>(decl))
               break;
         }
      }
   } while ((dc = dc->getParent()));

   return false;
}

/// Get the most optimal resilience expansion for the body of this function.
/// If the body is able to be inlined into functions in other resilience
/// domains, this ensures that only sufficiently-conservative access patterns
/// are used.
ResilienceExpansion DeclContext::getResilienceExpansion() const {
   auto &context = getAstContext();
   return evaluateOrDefault(context.evaluator,
                            ResilienceExpansionRequest { const_cast<DeclContext *>(this) },
                            ResilienceExpansion::Minimal);
}

llvm::Expected<ResilienceExpansion>
ResilienceExpansionRequest::evaluate(Evaluator &evaluator,
                                     DeclContext *context) const {
   for (const auto *dc = context->getLocalContext(); dc && dc->isLocalContext();
        dc = dc->getParent()) {
      // Default argument initializer contexts have their resilience expansion
      // set when they're type checked.
      if (isa<DefaultArgumentInitializer>(dc)) {
         dc = dc->getParent();

         auto *VD = cast<ValueDecl>(dc->getAsDecl());
         assert(VD->hasParameterList());

         auto access =
            VD->getFormalAccessScope(/*useDC=*/nullptr,
               /*treatUsableFromInlineAsPublic=*/true);

         if (access.isPublic())
            return ResilienceExpansion::Minimal;

         return ResilienceExpansion::Maximal;
      }

      // Stored property initializer contexts use minimal resilience expansion
      // if the type is formally fixed layout.
      if (isa<PatternBindingInitializer>(dc)) {
         if (auto *NTD = dyn_cast<NominalTypeDecl>(dc->getParent())) {
            auto nominalAccess =
               NTD->getFormalAccessScope(/*useDC=*/nullptr,
                  /*treatUsableFromInlineAsPublic=*/true);
            if (!nominalAccess.isPublic())
               return ResilienceExpansion::Maximal;

            if (NTD->isFormallyResilient())
               return ResilienceExpansion::Maximal;

            return ResilienceExpansion::Minimal;
         }
      }

      if (auto *AFD = dyn_cast<AbstractFunctionDecl>(dc)) {
         // If the function is a nested function, we will serialize its body if
         // we serialize the parent's body.
         if (AFD->getDeclContext()->isLocalContext())
            continue;

         auto funcAccess =
            AFD->getFormalAccessScope(/*useDC=*/nullptr,
               /*treatUsableFromInlineAsPublic=*/true);

         // If the function is not externally visible, we will not be serializing
         // its body.
         if (!funcAccess.isPublic())
            break;

         // If the function is public, @_transparent implies @inlinable.
         if (AFD->isTransparent())
            return ResilienceExpansion::Minimal;

         if (AFD->getAttrs().hasAttribute<InlinableAttr>())
            return ResilienceExpansion::Minimal;

         if (AFD->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>())
            return ResilienceExpansion::Minimal;

         // If a property or subscript is @inlinable or @_alwaysEmitIntoClient,
         // the accessors are @inlinable or @_alwaysEmitIntoClient also.
         if (auto accessor = dyn_cast<AccessorDecl>(AFD)) {
            auto *storage = accessor->getStorage();
            if (storage->getAttrs().getAttribute<InlinableAttr>())
               return ResilienceExpansion::Minimal;
            if (storage->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>())
               return ResilienceExpansion::Minimal;
         }
      }
   }

   return ResilienceExpansion::Maximal;
}

/// Determine whether the innermost context is generic.
bool DeclContext::isInnermostContextGeneric() const {
   if (auto Decl = getAsDecl())
      if (auto GC = Decl->getAsGenericContext())
         return GC->isGeneric();
   return false;
}

bool
DeclContext::isCascadingContextForLookup(bool functionsAreNonCascading) const {
   // FIXME: This is explicitly checking for attributes in some cases because
   // it can be called before access control is computed.
   switch (getContextKind()) {
      case DeclContextKind::AbstractClosureExpr:
         break;

      case DeclContextKind::SerializedLocal:
         llvm_unreachable("should not perform lookups in deserialized contexts");

      case DeclContextKind::Initializer:
         // Default arguments still require a type.
         if (isa<DefaultArgumentInitializer>(this))
            return false;
         break;

      case DeclContextKind::TopLevelCodeDecl:
         // FIXME: Pattern initializers at top-level scope end up here.
         return true;

      case DeclContextKind::AbstractFunctionDecl:
         if (functionsAreNonCascading)
            return false;
         break;

      case DeclContextKind::SubscriptDecl:
         break;

      case DeclContextKind::EnumElementDecl:
         break;

      case DeclContextKind::Module:
      case DeclContextKind::FileUnit:
         return true;

      case DeclContextKind::GenericTypeDecl:
         break;

      case DeclContextKind::ExtensionDecl:
         return true;
   }

   return getParent()->isCascadingContextForLookup(true);
}

unsigned DeclContext::getSyntacticDepth() const {
   // Module scope == depth 0.
   if (isModuleScopeContext())
      return 0;

   return 1 + getParent()->getSyntacticDepth();
}

unsigned DeclContext::getSemanticDepth() const {
   // For extensions, count the depth of the nominal type being extended.
   if (isa<ExtensionDecl>(this)) {
      if (auto nominal = getSelfNominalTypeDecl())
         return nominal->getSemanticDepth();

      return 1;
   }

   // Module scope == depth 0.
   if (isModuleScopeContext())
      return 0;

   return 1 + getParent()->getSemanticDepth();
}

bool DeclContext::mayContainMembersAccessedByDynamicLookup() const {
   // Members of non-generic classes and class extensions can be found by
   /// dynamic lookup.
   if (auto *CD = getSelfClassDecl())
      return !CD->isGenericContext();

   // Members of @objc protocols (but not protocol extensions) can be
   // found by dynamic lookup.
   /// @todo
//  if (auto *PD = dyn_cast<InterfaceDecl>(this))
//      return PD->getAttrs().hasAttribute<ObjCAttr>();

   return false;
}

bool DeclContext::canBeParentOfExtension() const {
   return isa<SourceFile>(this);
}

bool DeclContext::walkContext(AstWalker &Walker) {
   switch (getContextKind()) {
      case DeclContextKind::Module:
         return cast<ModuleDecl>(this)->walk(Walker);
      case DeclContextKind::FileUnit:
         return cast<FileUnit>(this)->walk(Walker);
      case DeclContextKind::AbstractClosureExpr:
         return cast<AbstractClosureExpr>(this)->walk(Walker);
      case DeclContextKind::GenericTypeDecl:
         return cast<GenericTypeDecl>(this)->walk(Walker);
      case DeclContextKind::ExtensionDecl:
         return cast<ExtensionDecl>(this)->walk(Walker);
      case DeclContextKind::TopLevelCodeDecl:
         return cast<TopLevelCodeDecl>(this)->walk(Walker);
      case DeclContextKind::AbstractFunctionDecl:
         return cast<AbstractFunctionDecl>(this)->walk(Walker);
      case DeclContextKind::SubscriptDecl:
         return cast<SubscriptDecl>(this)->walk(Walker);
      case DeclContextKind::EnumElementDecl:
         return cast<EnumElementDecl>(this)->walk(Walker);
      case DeclContextKind::SerializedLocal:
         llvm_unreachable("walk is unimplemented for deserialized contexts");
      case DeclContextKind::Initializer:
         // Is there any point in trying to walk the expression?
         return false;
   }
   llvm_unreachable("bad DeclContextKind");
}

void DeclContext::dumpContext() const {
   printContext(llvm::errs());
}

void AccessScope::dump() const {
   llvm::errs() << getAccessLevelSpelling(accessLevelForDiagnostics()) << ": ";

   if (isPublic()) {
      llvm::errs() << "(null)\n";
      return;
   }

   if (auto *file = dyn_cast<SourceFile>(getDeclContext())) {
      llvm::errs() << "file '" << file->getFilename() << "'\n";
      return;
   }

   if (auto *decl = getDeclContext()->getAsDecl()) {
      llvm::errs() << Decl::getKindName(decl->getKind()) << " ";
      if (auto *ext = dyn_cast<ExtensionDecl>(decl))
         llvm::errs() << ext->getExtendedNominal()->getName();
      else if (auto *named = dyn_cast<ValueDecl>(decl))
         llvm::errs() << named->getFullName();
      else
         llvm::errs() << (const void *)decl;

      SourceLoc loc = decl->getLoc();
      if (loc.isValid()) {
         llvm::errs() << " at ";
         loc.print(llvm::errs(), decl->getAstContext().SourceMgr);
      }
      llvm::errs() << "\n";

      return;
   }

   // If all else fails, dump the DeclContext tree.
   getDeclContext()->printContext(llvm::errs());
}

template <typename DCType>
static unsigned getLineNumber(DCType *DC) {
   SourceLoc loc = DC->getLoc();
   if (loc.isInvalid())
      return 0;

   const AstContext &ctx = static_cast<const DeclContext *>(DC)->getAstContext();
   return ctx.SourceMgr.getLineAndColumn(loc).first;
}

unsigned DeclContext::printContext(raw_ostream &OS, const unsigned indent,
                                   const bool onlyAPartialLine) const {
   unsigned Depth = 0;
   if (!onlyAPartialLine)
      if (auto *P = getParent())
         Depth = P->printContext(OS, indent);

   const char *Kind;
   switch (getContextKind()) {
      case DeclContextKind::Module:           Kind = "Module"; break;
      case DeclContextKind::FileUnit:         Kind = "FileUnit"; break;
      case DeclContextKind::SerializedLocal:  Kind = "Serialized Local"; break;
      case DeclContextKind::AbstractClosureExpr:
         Kind = "AbstractClosureExpr";
         break;
      case DeclContextKind::GenericTypeDecl:
         switch (cast<GenericTypeDecl>(this)->getKind()) {
#define DECL(ID, PARENT) \
    case DeclKind::ID: Kind = #ID "Decl"; break;
#include "polarphp/ast/DeclNodesDef.h"
         }
         break;
      case DeclContextKind::ExtensionDecl:    Kind = "ExtensionDecl"; break;
      case DeclContextKind::TopLevelCodeDecl: Kind = "TopLevelCodeDecl"; break;
      case DeclContextKind::Initializer:      Kind = "Initializer"; break;
      case DeclContextKind::AbstractFunctionDecl:
         Kind = "AbstractFunctionDecl";
         break;
      case DeclContextKind::SubscriptDecl:    Kind = "SubscriptDecl"; break;
      case DeclContextKind::EnumElementDecl:  Kind = "EnumElementDecl"; break;
   }
   OS.indent(Depth*2 + indent) << (void*)this << " " << Kind;

   switch (getContextKind()) {
      case DeclContextKind::Module:
         OS << " name=" << cast<ModuleDecl>(this)->getName();
         break;
      case DeclContextKind::FileUnit:
         switch (cast<FileUnit>(this)->getKind()) {
            case FileUnitKind::Builtin:
               OS << " Builtin";
               break;
            case FileUnitKind::Source:
               OS << " file=\"" << cast<SourceFile>(this)->getFilename() << "\"";
               break;
            case FileUnitKind::SerializedAST:
            case FileUnitKind::ClangModule:
            case FileUnitKind::DWARFModule:
               OS << " file=\"" << cast<LoadedFile>(this)->getFilename() << "\"";
               break;
         }
         break;
      case DeclContextKind::AbstractClosureExpr:
         OS << " line=" << getLineNumber(cast<AbstractClosureExpr>(this));
         OS << " : " << cast<AbstractClosureExpr>(this)->getType();
         break;
      case DeclContextKind::GenericTypeDecl:
         OS << " name=" << cast<GenericTypeDecl>(this)->getName();
         break;
      case DeclContextKind::ExtensionDecl:
         OS << " line=" << getLineNumber(cast<ExtensionDecl>(this));
         OS << " base=" << cast<ExtensionDecl>(this)->getExtendedType();
         break;
      case DeclContextKind::TopLevelCodeDecl:
         OS << " line=" << getLineNumber(cast<TopLevelCodeDecl>(this));
         break;
      case DeclContextKind::AbstractFunctionDecl: {
         auto *AFD = cast<AbstractFunctionDecl>(this);
         OS << " name=" << AFD->getFullName();
         if (AFD->hasInterfaceType())
            OS << " : " << AFD->getInterfaceType();
         else
            OS << " : (no type set)";
         break;
      }
      case DeclContextKind::SubscriptDecl: {
         auto *SD = cast<SubscriptDecl>(this);
         OS << " name=" << SD->getBaseName();
         if (SD->hasInterfaceType())
            OS << " : " << SD->getInterfaceType();
         else
            OS << " : (no type set)";
         break;
      }
      case DeclContextKind::EnumElementDecl: {
         auto *EED = cast<EnumElementDecl>(this);
         OS << " name=" << EED->getBaseName();
         if (EED->hasInterfaceType())
            OS << " : " << EED->getInterfaceType();
         else
            OS << " : (no type set)";
         break;
      }
      case DeclContextKind::Initializer:
         switch (cast<Initializer>(this)->getInitializerKind()) {
            case InitializerKind::PatternBinding: {
               auto init = cast<PatternBindingInitializer>(this);
               OS << " PatternBinding 0x" << (void*) init->getBinding()
                  << " #" << init->getBindingIndex();
               break;
            }
            case InitializerKind::DefaultArgument: {
               auto init = cast<DefaultArgumentInitializer>(this);
               OS << " DefaultArgument index=" << init->getIndex();
               break;
            }
         }
         break;

      case DeclContextKind::SerializedLocal: {
         auto local = cast<SerializedLocalDeclContext>(this);
         switch (local->getLocalDeclContextKind()) {
            case LocalDeclContextKind::AbstractClosure: {
               auto serializedClosure = cast<SerializedAbstractClosureExpr>(local);
               OS << " closure : " << serializedClosure->getType();
               break;
            }
            case LocalDeclContextKind::DefaultArgumentInitializer: {
               auto init = cast<SerializedDefaultArgumentInitializer>(local);
               OS << "DefaultArgument index=" << init->getIndex();
               break;
            }
            case LocalDeclContextKind::PatternBindingInitializer: {
               auto init = cast<SerializedPatternBindingInitializer>(local);
               OS << " PatternBinding 0x" << (void*) init->getBinding()
                  << " #" << init->getBindingIndex();
               break;
            }
            case LocalDeclContextKind::TopLevelCodeDecl:
               OS << " TopLevelCode";
               break;
         }
      }
   }

   if (!onlyAPartialLine)
      OS << "\n";
   return Depth + 1;
}

const Decl *
IterableDeclContext::getDecl() const {
   switch (getIterableContextKind()) {
      case IterableDeclContextKind::NominalTypeDecl:
         return cast<NominalTypeDecl>(this);
         break;

      case IterableDeclContextKind::ExtensionDecl:
         return cast<ExtensionDecl>(this);
         break;
   }
   llvm_unreachable("Unhandled IterableDeclContextKind in switch.");
}

AstContext &IterableDeclContext::getAstContext() const {
   return getDecl()->getAstContext();
}

DeclRange IterableDeclContext::getCurrentMembersWithoutLoading() const {
   return DeclRange(FirstDeclAndLazyMembers.getPointer(), nullptr);
}

DeclRange IterableDeclContext::getMembers() const {
   loadAllMembers();

   return getCurrentMembersWithoutLoading();
}

/// Add a member to this context.
void IterableDeclContext::addMember(Decl *member, Decl *Hint) {
   // Add the member to the list of declarations without notification.
   addMemberSilently(member, Hint);
   ++MemberCount;

   // Notify our parent declaration that we have added the member, which can
   // be used to update the lookup tables.
   switch (getIterableContextKind()) {
      case IterableDeclContextKind::NominalTypeDecl: {
         auto nominal = cast<NominalTypeDecl>(this);
         nominal->addedMember(member);
         assert(member->getDeclContext() == nominal &&
                "Added member to the wrong context");
         break;
      }

      case IterableDeclContextKind::ExtensionDecl: {
         auto ext = cast<ExtensionDecl>(this);
         ext->addedMember(member);
         assert(member->getDeclContext() == ext &&
                "Added member to the wrong context");
         break;
      }
   }
}

void IterableDeclContext::addMemberSilently(Decl *member, Decl *hint) const {
   assert(!isa<AccessorDecl>(member) && "Accessors should not be added here");
   assert(!member->NextDecl && "Already added to a container");

   // If there is a hint decl that specifies where to add this, just
   // link into the chain immediately following it.
   if (hint) {
      member->NextDecl = hint->NextDecl;
      hint->NextDecl = member;

      // If the hint was the last in the parent context's chain, update it.
      if (LastDeclAndKind.getPointer() == hint)
         LastDeclAndKind.setPointer(member);
      return;
   }

   if (auto last = LastDeclAndKind.getPointer()) {
      last->NextDecl = member;
      assert(last != member && "Simple cycle in decl list");
   } else {
      FirstDeclAndLazyMembers.setPointer(member);
   }
   LastDeclAndKind.setPointer(member);
}

void IterableDeclContext::setMemberLoader(LazyMemberLoader *loader,
                                          uint64_t contextData) {
   assert(!hasLazyMembers() && "already have lazy members");

   AstContext &ctx = getAstContext();
   auto contextInfo = ctx.getOrCreateLazyIterableContextData(this, loader);
   auto lazyMembers = FirstDeclAndLazyMembers.getInt() | LazyMembers::Present;
   FirstDeclAndLazyMembers.setInt(LazyMembers(lazyMembers));
   contextInfo->memberData = contextData;

   ++NumLazyIterableDeclContexts;
   ++NumUnloadedLazyIterableDeclContexts;
   // FIXME: (transitional) increment the redundant "always-on" counter.
   if (auto s = ctx.Stats) {
      ++s->getFrontendCounters().NumLazyIterableDeclContexts;
      ++s->getFrontendCounters().NumUnloadedLazyIterableDeclContexts;
   }
}
bool IterableDeclContext::hasUnparsedMembers() const {
   if (AddedParsedMembers)
      return false;

   if (!getDecl()->getDeclContext()->getParentSourceFile()) {
      // There will never be any parsed members to add, so set the flag to say
      // we are done so we can short-circuit next time.
      const_cast<IterableDeclContext *>(this)->AddedParsedMembers = 1;
      return false;
   }

   return true;
}

unsigned IterableDeclContext::getMemberCount() const {
   if (hasUnparsedMembers())
      loadAllMembers();
   return MemberCount;
}

void IterableDeclContext::loadAllMembers() const {
   AstContext &ctx = getAstContext();

   // For contexts within a source file, get the list of parsed members.
   if (getDecl()->getDeclContext()->getParentSourceFile()) {
      // Retrieve the parsed members. Even if we've already added the parsed
      // members to this context, this call is important for recording the
      // dependency edge.
      auto mutableThis = const_cast<IterableDeclContext *>(this);
      auto members = evaluateOrDefault(
         ctx.evaluator, ParseMembersRequest{mutableThis}, ArrayRef<Decl*>());
//
//      // If we haven't already done so, add these members to this context.
//      if (!AddedParsedMembers) {
//         mutableThis->AddedParsedMembers = 1;
//         for (auto member : members) {
//            mutableThis->addMember(member);
//         }
//      }
   }

   if (!hasLazyMembers())
      return;

   // Don't try to load all members re-entrant-ly.
   auto contextInfo = ctx.getOrCreateLazyIterableContextData(this,
      /*lazyLoader=*/nullptr);
   auto lazyMembers = FirstDeclAndLazyMembers.getInt() & ~LazyMembers::Present;
   FirstDeclAndLazyMembers.setInt(LazyMembers(lazyMembers));

   const Decl *container = getDecl();
   contextInfo->loader->loadAllMembers(const_cast<Decl *>(container),
                                       contextInfo->memberData);

   --NumUnloadedLazyIterableDeclContexts;
   // FIXME: (transitional) decrement the redundant "always-on" counter.
   if (auto s = ctx.Stats)
      s->getFrontendCounters().NumUnloadedLazyIterableDeclContexts--;
}

bool IterableDeclContext::wasDeserialized() const {
   const DeclContext *DC = cast<DeclContext>(getDecl());
   if (auto F = dyn_cast<FileUnit>(DC->getModuleScopeContext())) {
      return F->getKind() == FileUnitKind::SerializedAST;
   }
   return false;
}

bool IterableDeclContext::classof(const Decl *D) {
   switch (D->getKind()) {
      default: return false;
#define DECL(ID, PARENT) // See previous line
#define ITERABLE_DECL(ID, PARENT) \
  case DeclKind::ID: return true;
#include "polarphp/ast/DeclNodesDef.h"
   }
}

IterableDeclContext *
IterableDeclContext::castDeclToIterableDeclContext(const Decl *D) {
   switch (D->getKind()) {
      default: llvm_unreachable("Decl is not a IterableDeclContext.");
#define DECL(ID, PARENT) // See previous line
#define ITERABLE_DECL(ID, PARENT) \
  case DeclKind::ID: \
    return const_cast<IterableDeclContext *>( \
        static_cast<const IterableDeclContext*>(cast<ID##Decl>(D)));
#include "polarphp/ast/DeclNodesDef.h"
   }
}

/// Return the DeclContext to compare when checking private access in
/// Swift 4 mode. The context returned is the type declaration if the context
/// and the type declaration are in the same file, otherwise it is the types
/// last extension in the source file. If the context does not refer to a
/// declaration or extension, the supplied context is returned.
static const DeclContext *
getPrivateDeclContext(const DeclContext *DC, const SourceFile *useSF) {
   auto NTD = DC->getSelfNominalTypeDecl();
   if (!NTD)
      return DC;

   // use the type declaration as the private scope if it is in the same
   // file as useSF. This occurs for both extensions and declarations.
   if (NTD->getParentSourceFile() == useSF)
      return NTD;

   // Otherwise use the last extension declaration in the same file.
   const DeclContext *lastExtension = nullptr;
   for (ExtensionDecl *ED : NTD->getExtensions())
      if (ED->getParentSourceFile() == useSF)
         lastExtension = ED;

   // If there's no last extension, return the supplied context.
   return lastExtension ? lastExtension : DC;
}

AccessScope::AccessScope(const DeclContext *DC, bool isPrivate)
   : Value(DC, isPrivate) {
   if (isPrivate) {
      DC = getPrivateDeclContext(DC, DC->getParentSourceFile());
      Value.setPointer(DC);
   }
   if (!DC || isa<ModuleDecl>(DC))
      assert(!isPrivate && "public or internal scope can't be private");
}

bool AccessScope::isFileScope() const {
   auto DC = getDeclContext();
   return DC && isa<FileUnit>(DC);
}

bool AccessScope::isInternal() const {
   auto DC = getDeclContext();
   return DC && isa<ModuleDecl>(DC);
}

AccessLevel AccessScope::accessLevelForDiagnostics() const {
   if (isPublic())
      return AccessLevel::Public;
   if (isa<ModuleDecl>(getDeclContext()))
      return AccessLevel::Internal;
   if (getDeclContext()->isModuleScopeContext()) {
      return isPrivate() ? AccessLevel::Private : AccessLevel::FilePrivate;
   }

   return AccessLevel::Private;
}

bool AccessScope::allowsPrivateAccess(const DeclContext *useDC, const DeclContext *sourceDC) {
   // Check the lexical scope.
   if (useDC->isChildContextOf(sourceDC))
      return true;

   // Do not allow access if the sourceDC is in a different file
   auto useSF = useDC->getParentSourceFile();
   if (useSF != sourceDC->getParentSourceFile())
      return false;

   // Do not allow access if the sourceDC does not represent a type.
   auto sourceNTD = sourceDC->getSelfNominalTypeDecl();
   if (!sourceNTD)
      return false;

   // Compare the private scopes and iterate over the parent types.
   sourceDC = getPrivateDeclContext(sourceDC, useSF);
   while (!useDC->isModuleContext()) {
      useDC = getPrivateDeclContext(useDC, useSF);
      if (useDC == sourceDC)
         return true;

      // Get the parent type. If the context represents a type, look at the types
      // declaring context instead of the contexts parent. This will crawl up
      // the type hierarchy in nested extensions correctly.
      if (auto NTD = useDC->getSelfNominalTypeDecl())
         useDC = NTD->getDeclContext();
      else
         useDC = useDC->getParent();
   }

   return false;
}

DeclContext *Decl::getDeclContextForModule() const {
   if (auto module = dyn_cast<ModuleDecl>(this))
      return const_cast<ModuleDecl *>(module);

   return nullptr;
}

DeclContextKind DeclContext::getContextKind() const {
   switch (ParentAndKind.getInt()) {
      case ASTHierarchy::Expr:
         return DeclContextKind::AbstractClosureExpr;
      case ASTHierarchy::Initializer:
         return DeclContextKind::Initializer;
      case ASTHierarchy::SerializedLocal:
         return DeclContextKind::SerializedLocal;
      case ASTHierarchy::FileUnit:
         return DeclContextKind::FileUnit;
      case ASTHierarchy::Decl: {
         auto decl = reinterpret_cast<const Decl*>(this + 1);
         if (isa<AbstractFunctionDecl>(decl))
            return DeclContextKind::AbstractFunctionDecl;
         if (isa<GenericTypeDecl>(decl))
            return DeclContextKind::GenericTypeDecl;
         switch (decl->getKind()) {
            case DeclKind::Module:
               return DeclContextKind::Module;
            case DeclKind::TopLevelCode:
               return DeclContextKind::TopLevelCodeDecl;
            case DeclKind::Subscript:
               return DeclContextKind::SubscriptDecl;
            case DeclKind::EnumElement:
               return DeclContextKind::EnumElementDecl;
            case DeclKind::Extension:
               return DeclContextKind::ExtensionDecl;
            default:
               llvm_unreachable("Unhandled Decl kind");
         }
      }
   }
   llvm_unreachable("Unhandled DeclContext ASTHierarchy");
}

bool DeclContext::hasValueSemantics() const {
   if (getExtendedInterfaceDecl())
      return !isClassConstrainedInterfaceExtension();
   return !getDeclaredInterfaceType()->hasReferenceSemantics();
}

bool DeclContext::isClassConstrainedInterfaceExtension() const {
   if (getExtendedInterfaceDecl()) {
      auto ED = cast<ExtensionDecl>(this);
      return ED->getGenericSignature()->requiresClass(ED->getSelfInterfaceType());
   }
   return false;
}

SourceLoc extractNearestSourceLoc(const DeclContext *dc) {
   switch (dc->getContextKind()) {
      case DeclContextKind::AbstractFunctionDecl:
      case DeclContextKind::EnumElementDecl:
      case DeclContextKind::ExtensionDecl:
      case DeclContextKind::GenericTypeDecl:
      case DeclContextKind::Module:
      case DeclContextKind::SubscriptDecl:
      case DeclContextKind::TopLevelCodeDecl:
         return extractNearestSourceLoc(dc->getAsDecl());

      case DeclContextKind::AbstractClosureExpr: {
         SourceLoc loc = cast<AbstractClosureExpr>(dc)->getLoc();
         if (loc.isValid())
            return loc;
         return extractNearestSourceLoc(dc->getParent());
      }

      case DeclContextKind::FileUnit:
         return SourceLoc();

      case DeclContextKind::Initializer:
      case DeclContextKind::SerializedLocal:
         return extractNearestSourceLoc(dc->getParent());
   }
   llvm_unreachable("Unhandled DeclCopntextKindin switch");
}

#define DECL(Id, Parent) \
  static_assert(!std::is_base_of<DeclContext, Id##Decl>::value, \
                "Non-context Decl node has context?");
#define CONTEXT_DECL(Id, Parent) \
  static_assert(alignof(DeclContext) == alignof(Id##Decl), "Alignment error"); \
  static_assert(std::is_base_of<DeclContext, Id##Decl>::value, \
                "CONTEXT_DECL nodes must inherit from DeclContext");
#define CONTEXT_VALUE_DECL(Id, Parent) \
  static_assert(alignof(DeclContext) == alignof(Id##Decl), "Alignment error"); \
  static_assert(std::is_base_of<DeclContext, Id##Decl>::value, \
                "CONTEXT_VALUE_DECL nodes must inherit from DeclContext");
#include "polarphp/ast/DeclNodesDef.h"

#define EXPR(Id, Parent) \
  static_assert(!std::is_base_of<DeclContext, Id##Expr>::value, \
                "Non-context Expr node has context?");
#define CONTEXT_EXPR(Id, Parent) \
  static_assert(alignof(DeclContext) == alignof(Id##Expr), "Alignment error"); \
  static_assert(std::is_base_of<DeclContext, Id##Expr>::value, \
                "CONTEXT_EXPR nodes must inherit from DeclContext");
#include "polarphp/ast/ExprNodesDef.h"

#ifndef NDEBUG
// XXX -- static_cast is not static enough for use with static_assert().
// DO verify this by temporarily breaking a Decl or Expr.
// DO NOT assume that the compiler will emit this code blindly.
POLAR_CONSTRUCTOR
static void verify_DeclContext_is_start_of_node() {
   auto decl = reinterpret_cast<Decl*>(0x1000 + sizeof(DeclContext));
#define DECL(Id, Parent)
#define CONTEXT_DECL(Id, Parent) \
  assert(reinterpret_cast<DeclContext*>(0x1000) == \
         static_cast<Id##Decl*>(decl));
#define CONTEXT_VALUE_DECL(Id, Parent) \
  assert(reinterpret_cast<DeclContext*>(0x1000) == \
         static_cast<Id##Decl*>(decl));
#include "polarphp/ast/DeclNodesDef.h"

   auto expr = reinterpret_cast<Expr*>(0x1000 + sizeof(DeclContext));
#define EXPR(Id, Parent)
#define CONTEXT_EXPR(Id, Parent) \
  assert(reinterpret_cast<DeclContext*>(0x1000) == \
         static_cast<Id##Expr*>(expr));
#include "polarphp/ast/ExprNodesDef.h"
}
#endif

void simple_display(llvm::raw_ostream &out,
                    const IterableDeclContext *idc) {
   simple_display(out, idc->getDecl());
}

SourceLoc extractNearestSourceLoc(const IterableDeclContext *idc) {
   return extractNearestSourceLoc(idc->getDecl());
}

} // polar